package xcmg.device.service.warehouse;

import com.github.pagehelper.PageInfo;
import xcmg.device.service.order.SubcontractingOutService;
import xcmg.device.util.CommonUtils;
import yb.ecp.fast.infra.util.PageHelperPlus;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import xcmg.device.dao.entity.barcode.BarcodeManageDO;
import xcmg.device.dao.entity.company.CompanyInfoDO;
import xcmg.device.dao.entity.delivery.DeliveryNoteDO;
import xcmg.device.dao.entity.delivery.DeliveryReceiptDO;
import xcmg.device.dao.entity.delivery.DeliveryReceiptMaterialDO;
import xcmg.device.dao.entity.sale.SaleIntentionDetailDO;
import xcmg.device.dao.entity.warehouse.WarehouseDeliveryDO;
import xcmg.device.dao.entity.warehouse.WarehouseDeliveryDetailDO;
import xcmg.device.dao.entity.warehouse.WarehouseDeliveryRecordDO;
import xcmg.device.dao.entity.warehouse.WarehouseInventoryDO;
import xcmg.device.dao.mapper.BarcodeManageMapper;
import xcmg.device.dao.mapper.CompanyInfoMapper;
import xcmg.device.dao.mapper.SaleIntentionDetailMapper;
import xcmg.device.dao.mapper.delivery.DeliveryNoteMapper;
import xcmg.device.dao.mapper.delivery.DeliveryReceiptLinkMapper;
import xcmg.device.dao.mapper.delivery.DeliveryReceiptMapper;
import xcmg.device.dao.mapper.delivery.DeliveryReceiptMaterialMapper;
import xcmg.device.dao.mapper.warehouse.WarehouseAreaLocationDOMapper;
import xcmg.device.dao.mapper.warehouse.WarehouseDOMapper;
import xcmg.device.dao.mapper.warehouse.WarehouseDeliveryDetailMapper;
import xcmg.device.dao.mapper.warehouse.WarehouseDeliveryMapper;
import xcmg.device.dao.mapper.warehouse.WarehouseDeliveryRecordMapper;
import xcmg.device.infra.ErrorCode;
import xcmg.device.infra.ExportUtil;
import xcmg.device.infra.enums.BarcodeStatus;
import xcmg.device.infra.enums.BillDesc;
import xcmg.device.service.abnormal.AbnormalOutService;
import xcmg.device.service.agent.AgentAllotDetailService;
import xcmg.device.service.agent.ServiceBorrowOutService;
import xcmg.device.service.barcode.BarcodeService;
import xcmg.device.service.buyBack.BackOutboundService;
import xcmg.device.service.delivery.DeliveryNoteService;
import xcmg.device.service.delivery.DeliveryReceiptMaterialService;
import xcmg.device.service.logistics.SendBillService;
import xcmg.device.service.materialsSchedule.MaterialsScheduleService;
import xcmg.device.service.returnMaterial.ReturnMaterialService;
import xcmg.device.service.sale.SalesBillOutService;
import xcmg.device.service.threeGuaranteesPur.ThreeGuaranteesOutService;
import xcmg.device.service.vo.barcode.BarcodeManageVO;
import xcmg.device.service.vo.barcode.SplitNumVO;
import xcmg.device.service.vo.warehouse.InOutNumVO;
import xcmg.device.service.vo.warehouse.WarehouseDeliveryAddVO;
import xcmg.device.service.vo.warehouse.WarehouseDeliveryDetailVO;
import xcmg.device.service.vo.warehouse.WarehouseDeliveryRecordAddVO;
import xcmg.device.service.vo.warehouse.WarehouseDeliveryRecordBatchAddVO;
import xcmg.device.service.vo.warehouse.WarehouseDeliveryRecordVO;
import xcmg.device.service.warehouse.allot.RegionAllotDetailService;
import xcmg.device.util.CompanyUtil;
import yb.ecp.fast.feign.FastGenClient;
import yb.ecp.fast.infra.infra.ActionResult;
import yb.ecp.fast.infra.infra.PageCommonVO;
import yb.ecp.fast.infra.infra.SearchCommonVO;
import yb.ecp.fast.infra.infra.log.LogHelper;
import yb.ecp.fast.infra.util.ListUtil;
import yb.ecp.fast.infra.util.StringUtil;

import javax.servlet.http.HttpServletResponse;
import java.math.BigDecimal;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

@Service
public class WarehouseDeliveryRecordService {

    @Autowired
    private WarehouseDeliveryRecordMapper warehouseDeliveryRecordMapper;

    @Autowired
    private WarehouseInventoryService warehouseInventoryService;

    @Autowired
    private WarehouseDeliveryDetailService warehouseDeliveryDetailService;

    @Autowired
    private FastGenClient fastGenClient;

    @Autowired
    private BarcodeManageMapper barcodeManageMapper;

    @Autowired
    private WarehouseDeliveryDetailMapper warehouseDeliveryDetailMapper;

    @Autowired
    private BarcodeService barcodeService;

    @Autowired
    private CommonService commonService;

    @Autowired
    private HttpServletResponse response;

    @Autowired
    private RegionAllotDetailService regionAllotDetailService;

    @Autowired
    private AbnormalOutService abnormalOutService;

    @Autowired
    private DeliveryNoteService deliveryNoteService;

    @Autowired
    private AgentAllotDetailService agentAllotDetailService;

    @Autowired
    private WarehouseDeliveryMapper warehouseDeliveryMapper;

    @Autowired
    private ThreeGuaranteesOutService threeGuaranteesOutService;

    @Autowired
    private WarehouseAreaLocationDOMapper warehouseAreaLocationDOMapper;

    @Autowired
    private WarehouseDeliveryService warehouseDeliveryService;

    @Autowired
    private MaterialsScheduleService materialsScheduleService;

    @Autowired
    private DeliveryReceiptMapper deliveryReceiptMapper;

    @Autowired
    private DeliveryReceiptMaterialMapper deliveryReceiptMaterialMapper;

    @Autowired
    private DeliveryReceiptMaterialService deliveryReceiptMaterialService;

    @Autowired
    private DeliveryReceiptLinkMapper deliveryReceiptLinkMapper;
    @Autowired
    private BackOutboundService backOutboundService;
    @Autowired
    private ServiceBorrowOutService serviceBorrowOutService;
    @Autowired
    private SalesBillOutService salesOutBillService;
    @Autowired
    private CompanyInfoMapper companyInfoMapper;
    @Autowired
    private WarehouseDOMapper warehouseDOMapper;

    @Autowired
    private SaleIntentionDetailMapper saleIntentionDetailMapper;

    @Autowired
    private ReturnMaterialService returnMaterialService;

    @Autowired
    private SendBillService sendBillService;

    @Autowired
    private SubcontractingOutService subcontractingOutService;

    private static final Logger logger = LoggerFactory.getLogger(WarehouseDeliveryRecordService.class);
    /**
     * @Author: WangKe
     * @Description: 批量新增出库记录
     * @Date: 2018/3/14 0014
     */
    @Transactional(rollbackFor = Exception.class)
    public ErrorCode batchAdd(WarehouseDeliveryRecordBatchAddVO warehouseDeliveryRecordBatchAddVO, String userId, String orgId) throws Exception{
        if(ListUtil.isNullOrEmpty(warehouseDeliveryRecordBatchAddVO.getRecordList())){
            return ErrorCode.IllegalArument;
        }
        //实际出库数量不能大于计划出库数量
        WarehouseDeliveryRecordAddVO deliveryRecordAddVO = warehouseDeliveryRecordBatchAddVO.getRecordList().get(0);
        BarcodeManageDO barcode = barcodeManageMapper.item(deliveryRecordAddVO.getBarCode(), orgId);
        if(barcode == null){
            return ErrorCode.WarehouseBarcodeNotFound;
        }
        WarehouseDeliveryDetailVO model = new WarehouseDeliveryDetailVO();
        model.setBusinessOrder(deliveryRecordAddVO.getBusinessOrder());
        model.setMaterialNo(barcode.getMaterialsNo());
        model.setOrgId(orgId);
        List<WarehouseDeliveryDetailDO> deliveryDetailList = warehouseDeliveryDetailMapper.list(model);

        if(ListUtil.isNullOrEmpty(deliveryDetailList)){
            throw new Exception("此零件不属于出库单中零件");
        }

        //判断数量并自动拆分条码
        List<BarcodeManageVO> barcodeManageVOS=  splitBarcode(warehouseDeliveryRecordBatchAddVO, deliveryDetailList.get(0).getAmount(), userId, orgId);
        warehouseDeliveryRecordBatchAddVO.setBarcodeManageVOS(barcodeManageVOS);
        //批量插入
        ErrorCode errorCode = ErrorCode.Success;
        List<WarehouseDeliveryRecordAddVO> recordAddVOList = warehouseDeliveryRecordBatchAddVO.getRecordList();
        for(int i=0; i<recordAddVOList.size(); i++){
            WarehouseDeliveryRecordAddVO recordAddVO = recordAddVOList.get(i);
            //如果是发运交接单出库
            if (recordAddVO.getBusinessOrder().startsWith(BillDesc.DeliveryReceiptNo.getDesc())
            || recordAddVO.getBusinessOrder().startsWith(BillDesc.JCKDeliveryReceiptNo.getDesc())) {
                handleForDeliveryReceipt(recordAddVO, orgId, userId, i);

            } else {

                try {
                    boolean recordMachineType = false;
                    String businessOrder = recordAddVO.getBusinessOrder();
                    if (businessOrder != null && businessOrder.startsWith(BillDesc.DeliveryNo.getDesc())) {
                        recordMachineType = true;
                    }
                    errorCode = this.add(recordAddVO, userId, orgId, true,recordMachineType);
                } catch (Exception e) {
                    throw new Exception("index&&" + i + "&&" + e.getMessage());
                }
            }

            if(errorCode.getCode() != 0){
                throw new Exception("index&&"+i+"&&"+errorCode.getDesc());
            }
        }
        return errorCode;
    }

    /**
     * @Author: WangKe
     * @Description: 自动拆分条码
     * @Date: 2018/12/5 0005
     */
    private List<BarcodeManageVO> splitBarcode(WarehouseDeliveryRecordBatchAddVO warehouseDeliveryRecordBatchAddVO, BigDecimal amount, String userId, String orgId) throws Exception {
        BigDecimal splitAmount = BigDecimal.ZERO;
        List<BarcodeManageVO> results = new ArrayList<>();
        for (WarehouseDeliveryRecordAddVO recordAddVO : warehouseDeliveryRecordBatchAddVO.getRecordList()) {
            if (recordAddVO.getSplitAmount().compareTo(BigDecimal.ZERO) == 0) {
                splitAmount = splitAmount.add(recordAddVO.getAmount());
            } else {
                splitAmount = splitAmount.add(recordAddVO.getSplitAmount());
            }
            if (splitAmount.compareTo(amount) > 0) {
                throw new Exception("出库数量不能大于单据数量");
            }
            if (recordAddVO.getSplitAmount().compareTo(BigDecimal.ZERO) > 0) {
                SplitNumVO splitNumVO = new SplitNumVO(recordAddVO.getBarCode(), recordAddVO.getSplitAmount(), recordAddVO.getBusinessOrder());
                BarcodeManageVO barcodeManageVO = barcodeService.splitNum(splitNumVO, userId, orgId);
                recordAddVO.setBarCode(barcodeManageVO.getBarcode());
                recordAddVO.setAmount(barcodeManageVO.getCurrentQty());
                results.add(barcodeManageVO);
            }
        }
        return results;
    }

    @Transactional(rollbackFor = Exception.class)
    public void handleForDeliveryReceipt(WarehouseDeliveryRecordAddVO recordAddVO, String orgId, String userId, int i) throws Exception {
        BarcodeManageDO barcode = barcodeManageMapper.item(recordAddVO.getBarCode(), orgId);
        if (barcode == null) {
            throw new Exception("index&&" + i + "&&" + "条码不存在");
        }
        String materialNo = barcode.getMaterialsNo();
        DeliveryReceiptDO deliveryReceiptDO = deliveryReceiptMapper.itemByNo(recordAddVO.getBusinessOrder());
        if (deliveryReceiptDO == null) {
            throw new Exception("index&&" + i + "&&" + "发运交接单不存在");
        }

        Integer count = deliveryReceiptMaterialMapper.findCountByMaterialNo(recordAddVO.getBusinessOrder(), materialNo);
        logger.info("findCountByMaterialNo:" + count);

        if (count != null && count >1) {
            throw new Exception("index&&" + i + "&&" + "发运交接单零件编码重复，请使用业务单据出库");
        }

        DeliveryReceiptMaterialDO deliveryDetailDO = deliveryReceiptMaterialMapper.findByMaterialNo(recordAddVO.getBusinessOrder(), materialNo);
        if (deliveryDetailDO == null) {
            throw new Exception("index&&" + i + "&&" + "发运交接单下此零件不存在");
        }
        BigDecimal nowAmount = deliveryDetailDO.getOutQty().add(recordAddVO.getAmount());
        if (nowAmount.compareTo(deliveryDetailDO.getQty()) > 0) {
            throw new Exception("index&&" + i + "&&" + "本次入库数量大于剩余数量");
        }
        List<WarehouseDeliveryDetailDO> deliveryDetailDOList = null;
        if (BillDesc.DeliveryNo.getDesc().equals(deliveryReceiptDO.getBillType())) {
            deliveryDetailDOList = warehouseDeliveryDetailMapper.listReceiptDeliveryNote(recordAddVO.getBusinessOrder(), materialNo, orgId);
        }
        if (BillDesc.ThreeOut.getDesc().equals(deliveryReceiptDO.getBillType())) {
            deliveryDetailDOList = warehouseDeliveryDetailMapper.listReceiptThreeOut(recordAddVO.getBusinessOrder(), materialNo, orgId);
        }
        if (BillDesc.RegionAllot.getDesc().equals(deliveryReceiptDO.getBillType())) {
            deliveryDetailDOList = warehouseDeliveryDetailMapper.listReceiptRegionAllot(recordAddVO.getBusinessOrder(), materialNo, orgId);
        }
        if (BillDesc.AbnormalOutNo.getDesc().equals(deliveryReceiptDO.getBillType())) {
            deliveryDetailDOList = warehouseDeliveryDetailMapper.listReceiptAbnormalOut(recordAddVO.getBusinessOrder(), materialNo, orgId);
        }
        if (ListUtil.isNullOrEmpty(deliveryDetailDOList)) {
            throw new Exception("index&&" + i + "&&" + "发运交接单下未找到零件详情");
        }
        ErrorCode errorCode;
        BigDecimal outAmount;
        BigDecimal remainAmount;
        for (WarehouseDeliveryDetailDO detailDO : deliveryDetailDOList) {
            BigDecimal subAmount = detailDO.getAmount().subtract(detailDO.getRealAmount());
            if (subAmount.compareTo(recordAddVO.getAmount()) >= 0) {
                outAmount = recordAddVO.getAmount();
            } else {
                outAmount = subAmount;
            }
            remainAmount = recordAddVO.getAmount().subtract(outAmount);
            recordAddVO.setAmount(remainAmount);
            boolean isLast = remainAmount.compareTo(BigDecimal.ZERO) == 0;

            WarehouseDeliveryRecordAddVO newRecordAddVO = new WarehouseDeliveryRecordAddVO();
            newRecordAddVO.setBusinessOrder(detailDO.getBusinessOrder());
            newRecordAddVO.setAmount(outAmount);
            newRecordAddVO.setBarCode(recordAddVO.getBarCode());
            newRecordAddVO.setDeliveryReceiptNo(recordAddVO.getBusinessOrder());
            try {
                boolean recordMachineType = false;
                String businessOrder = recordAddVO.getBusinessOrder();
                //如果是进出口公司的发运交接单出库，复制销售订单中的适用机型到条码表中
                if (businessOrder.startsWith(BillDesc.DeliveryReceiptNo.getDesc())
                        || businessOrder.startsWith(BillDesc.JCKDeliveryReceiptNo.getDesc())) {
                    recordMachineType = true;
                }
                errorCode = this.add(newRecordAddVO, userId, orgId, isLast,recordMachineType);
            } catch (Exception e) {
                throw new Exception("index&&" + i + "&&" + e.getMessage());
            }

            if (errorCode.getCode() != 0) {
                throw new Exception("index&&" + i + "&&" + errorCode.getDesc());
            }

            if (isLast) {
                break;
            }
        }
        //更新发运交接单状态
        deliveryReceiptMaterialService.updateByOut(deliveryDetailDO, nowAmount);
    }

    /**
     * @param recordMachineType 是否需要记录适用机型到条码表中  true:记录   false:不记录
     * @Author: WangKe
     * @Description: 新增出库记录
     * @Date: 15:19 2018/1/17 0017
     */
    @Transactional(rollbackFor = Exception.class)
    public ErrorCode add(WarehouseDeliveryRecordAddVO warehouseDeliveryRecordVO, String userId, String orgId, boolean isLast, boolean recordMachineType) throws Exception{
        ActionResult<String> textResult = fastGenClient.textGuid();
        if (textResult.getCode() != ErrorCode.Success.getCode()) {
            return ErrorCode.IllegalArument;
        }

        //根据条码获取条码实体
        BarcodeManageDO barcode = barcodeManageMapper.item(warehouseDeliveryRecordVO.getBarCode(), orgId);
        if(barcode == null){
            return ErrorCode.WarehouseBarcodeNotFound;
        }
        if(barcode.getBarcodeFlag() == 0){
            return ErrorCode.TotalBarcodeNotEable;
        }
        //判断条码是否已经扫描出库
        if("2".equals(barcode.getBarcodeStatus())){
            return ErrorCode.WarehouseOutboundDuplicate;
        }

        //先判断库存表里是否有零件，零件数量是否够
        WarehouseInventoryDO warehouseInventoryDO = warehouseInventoryService.findByBarCode(warehouseDeliveryRecordVO.getBarCode(), orgId);
        if(warehouseInventoryDO == null || warehouseInventoryDO.getIsOut() == 1 ){
            return ErrorCode.WarehouseNotFound; //代表没有此零件
        }else if(warehouseInventoryDO.getStatus() == 1){
            return ErrorCode.WarehouseFrozen; //零件已冻结
        }else if(warehouseInventoryDO.getAmount().compareTo(warehouseDeliveryRecordVO.getAmount()) < 0){
            return ErrorCode.WarehouseAmountNotEqual; //代表零件数量不足
        }

        //根据业务单号和零件编码查询出库详情记录
        String businessOrder = warehouseDeliveryRecordVO.getBusinessOrder();
        businessOrder = businessOrder==null?"":businessOrder;
        String buinessSingle = "";

        if(businessOrder.length()>4){
            buinessSingle = CommonUtils.getEnglishPrefix(businessOrder);
        }

        String returnMaterialBusinessSingle = businessOrder.substring(0, 5);

        //查找出库事物主记录，判断是否冲销
        WarehouseDeliveryDO deliveryDO = warehouseDeliveryMapper.findByBusinessOrder(businessOrder, orgId);
        if(deliveryDO == null){
            throw new Exception("未找到相关联的出库事物单主记录");
        }
        if(deliveryDO.getReverseState() != null && (deliveryDO.getReverseState() == 1 || deliveryDO.getReverseState() == 2)){
            throw new Exception("业务单据已被冲销，不允许出库");
        }
        //判断单据是否已经是完成状态
        if( deliveryDO.getStatus() != null && deliveryDO.getStatus() == 4){
            throw new Exception("业务单据已作废！");
        }

        //判断单据是否已经是完成状态
        if(deliveryDO.getStatus() != null && (deliveryDO.getStatus() == 2 || deliveryDO.getStatus() == 3)){
            throw new Exception("业务单据已完成！");
        }
        //判断是否退货
        if(deliveryDO.getIsReturn() != null && deliveryDO.getIsReturn() == 1){
            throw new Exception("业务单据已被退货，不允许出库");
        }

        //判断零件是否属于调出仓库零件
        if(deliveryDO.getWarehouseCode() != null && !deliveryDO.getWarehouseCode().equals(warehouseInventoryDO.getWarehouseCode())){
            throw new Exception("此零件不属于调出仓库零件");
        }

        if (null != deliveryDO.getWarehouseCode()){
            CompanyInfoDO companyInfoDO = companyInfoMapper.item(orgId);
            Integer isBarcode = companyInfoDO.getIsBarcode();
            int countIsBarCode = warehouseDOMapper.countIsBarCode(orgId, deliveryDO.getWarehouseCode());
            if ((null == isBarcode || 0 == isBarcode) && countIsBarCode <= 0){//非条码化企业且仓库不允许条码化返回错误信息
                throw new Exception(ErrorCode.NonBarcodedOutboundNotAllowBarCodeEntry.getDesc());
            }
        }

        //判断零件是否属于调出仓库中库区零件
        if(deliveryDO.getOutArea() != null && !deliveryDO.getOutArea().equals(warehouseInventoryDO.getAreaCode())){
            throw new Exception("此零件不属于调出库区零件");
        }

        //判断零件是否属于出库单中零件
        WarehouseDeliveryDetailVO deliveryDetailVO = new WarehouseDeliveryDetailVO();
        deliveryDetailVO.setBusinessOrder(businessOrder);
        deliveryDetailVO.setMaterialNo(warehouseInventoryDO.getMaterialNo());
        deliveryDetailVO.setOrgId(orgId);
        List<WarehouseDeliveryDetailDO> list = warehouseDeliveryDetailMapper.list(deliveryDetailVO);
        if(ListUtil.isNullOrEmpty(list)){
            throw new Exception("此零件不属于出库单中零件");
        }
        boolean finishFlag = true;
        BigDecimal amount = BigDecimal.ZERO;
        for(WarehouseDeliveryDetailDO item: list) {
            amount = amount.add(item.getAmount() == null ? BigDecimal.ZERO : item.getAmount());
            finishFlag = finishFlag && (item.getStatus() == 2);
        }
        if (finishFlag) {
            throw new Exception("此零件状态已完成");
        }
        if (list.get(0).getStatus() == 3) {
            throw new Exception("此零件状态已结单");
        }
        if(StringUtil.isNullOrEmpty(warehouseDeliveryRecordVO.getDeliveryReceiptNo())){
            if(amount.compareTo(warehouseInventoryDO.getAmount()) < 0){
                throw new Exception("实际出库数量不能大于计划出库数量");
            }
        }
        
        WarehouseDeliveryRecordDO warehouseDeliveryRecordDO = new WarehouseDeliveryRecordDO();
        BeanUtils.copyProperties(warehouseInventoryDO, warehouseDeliveryRecordDO);

        warehouseDeliveryRecordDO.setBarCode(warehouseInventoryDO.getBarCode());
        warehouseDeliveryRecordDO.setBusinessOrder(businessOrder);
        warehouseDeliveryRecordDO.setBusinessSingle(buinessSingle);
        warehouseDeliveryRecordDO.setAmount(warehouseDeliveryRecordVO.getAmount());
        warehouseDeliveryRecordDO.setId(textResult.getValue());
        warehouseDeliveryRecordDO.setCreateDate(new Date());
        warehouseDeliveryRecordDO.setCreaterId(userId);
        warehouseDeliveryRecordDO.setOrgId(orgId);
        warehouseDeliveryRecordDO.setDeliveryOrder(deliveryDO.getDeliveryOrder());
        warehouseDeliveryRecordDO.setCreaterName(commonService.getUserName(userId));
        warehouseDeliveryRecordDO.setDeliveryReceiptNo(warehouseDeliveryRecordVO.getDeliveryReceiptNo());

        boolean isSuccess = warehouseDeliveryRecordMapper.insert(warehouseDeliveryRecordDO)>0;
        ErrorCode code = isSuccess? ErrorCode.Success: ErrorCode.Failure;

        //出库成功，库存表里相关记录更新
        if(isSuccess){
            if(isLast){
                //如果是发运交接单出库，有可能是一个条码分多次出库，在最后一次出库时更新条码已出库状态
                ErrorCode barcodeErrorCode = barcodeService.deliveryUpdateBarcode(businessOrder,warehouseDeliveryRecordDO.getBarCode(), BarcodeStatus.Status.OutStorage, orgId, userId,warehouseDeliveryRecordDO.getCreateDate());
                if(barcodeErrorCode.getCode() != 0){
                    throw new Exception("生成出库记录时，更新条码状态失败");
                }
                isSuccess = warehouseInventoryService.saveByOutbound(warehouseInventoryDO, warehouseDeliveryRecordDO, userId);
                if(!isSuccess){
                    throw new Exception("生成出库记录时，更新库存状态失败");
                }
            }
            //如果是进出口的发货通知单出库，则复制销售订单中的适用机型到条码表中
//            if (recordMachineType && StringUtils.isBlank(barcode.getMachineModel())) {
//                String jckOrgId = companyInfoMapper.getOrgIdBySapCode(CompanyUtil.JCK_SAP_CODE);
//                if (StringUtils.equals(jckOrgId,orgId)) {
//                    //获取发货通知单信息
//                    DeliveryNoteDO deliveryNoteDO = deliveryNoteMapper.itemByNo(businessOrder,orgId);
//                    if (deliveryNoteDO != null && StringUtils.isNotBlank(deliveryNoteDO.getSaleNo())) {
//                        //销售订单号
//                        String saleNo = deliveryNoteDO.getSaleNo();
//                        SaleIntentionDetailDO saleIntentionDetailDO = saleIntentionDetailMapper.selectByNo(saleNo, warehouseInventoryDO.getMaterialNo());
//                        if (saleIntentionDetailDO != null) {
//                            //获取对应销售订单中的适用机型
//                            String machineModel = saleIntentionDetailDO.getMachineModel();
//                            if (machineModel == null) {
//                                machineModel = "";
//                            }
//                            //更新条码表中的适用机型字段
//                            BarcodeManageDO barcodeManageDO = new BarcodeManageDO();
//                            barcodeManageDO.setBarcode(barcode.getBarcode());
//                            barcodeManageDO.setOrgId(barcode.getOrgId());
//                            barcodeManageDO.setMachineModel(machineModel);
//                            barcodeManageMapper.update(barcodeManageDO);
//                        }
//                    }
//
//                }
//            }
            Map<String, BigDecimal> map = warehouseDeliveryDetailService.updateByOutbound(warehouseDeliveryRecordDO.getDeliveryOrder(),
                    warehouseDeliveryRecordDO.getMaterialNo(), warehouseDeliveryRecordVO.getAmount(), orgId);
            isSuccess = map.get("success").intValue()==1;
            if(!isSuccess){
                throw new Exception("生成出库记录时，更新出库事物单状态失败");
            }

            LogHelper.monitor("buinessSingle------------->"+buinessSingle);
            LogHelper.monitor("returnMaterialBusinessSingle----------------->"+returnMaterialBusinessSingle);

            //更新出库业务单据状态
            BigDecimal realAmount = map.get("realAmount");
            Integer singleState = map.get("singleState").intValue();
            Integer totalState = map.get("totalState").intValue();
            boolean updateReceipt = StringUtil.isNullOrEmpty(warehouseDeliveryRecordVO.getDeliveryReceiptNo());
            if(BillDesc.RegionAllot.getDesc().equals(buinessSingle)){ //更新区域调拨单状态
                isSuccess = regionAllotDetailService.updateByOutbound(warehouseDeliveryRecordDO.getBusinessOrder(),
                        warehouseDeliveryRecordDO.getMaterialNo(), realAmount, singleState, totalState, orgId, updateReceipt);
                if(!isSuccess){
                    throw new Exception("生成出库记录时，更新区域调拨单和详情状态失败");
                }
            }else if(BillDesc.AbnormalOutNo.getDesc().equals(buinessSingle)){ //更新非正常出库单状态
                isSuccess = abnormalOutService.updateByOut(warehouseDeliveryRecordDO.getBusinessOrder(),
                        warehouseDeliveryRecordDO.getMaterialNo(), realAmount, singleState+"", totalState+"", orgId, warehouseDeliveryRecordVO.getAmount(), updateReceipt);
                if(!isSuccess){
                    throw new Exception("生成出库记录时，更新其它出库单和详情状态失败");
                }
            }else if(BillDesc.DeliveryNo.getDesc().equals(buinessSingle)){ //更新发货通知单状态
                isSuccess = deliveryNoteService.updateByDelivery(warehouseDeliveryRecordDO.getBusinessOrder(),
                        warehouseDeliveryRecordDO.getMaterialNo(), realAmount, singleState+"", totalState+"", orgId, updateReceipt);
                if(!isSuccess){
                    throw new Exception("生成出库记录时，更新发货通知单和详情状态失败");
                }
            }else if(BillDesc.AgentAllot.getDesc().equals(buinessSingle)){ //更新代理商间调拨单
                isSuccess = agentAllotDetailService.updateByOutbound(warehouseDeliveryRecordDO.getBusinessOrder(),
                        warehouseDeliveryRecordDO.getMaterialNo(), realAmount, singleState, totalState, orgId);
                if(!isSuccess){
                    throw new Exception("生成出库记录时，更新代理商间调拨单和详情状态失败");
                }
            }else if(BillDesc.ThreeOut.getDesc().equals(buinessSingle)){ //更新三包出库单
                isSuccess = threeGuaranteesOutService.updateByOutbound(warehouseDeliveryRecordDO.getBusinessOrder(),
                        warehouseDeliveryRecordDO.getMaterialNo(), realAmount, singleState, totalState, orgId, updateReceipt);
                if(!isSuccess){
                    throw new Exception("生成出库记录时，更新三包出库单和详情状态失败");
                }
            }else if(BillDesc.MaterialsCode.getDesc().equals(warehouseDeliveryRecordDO.getBusinessSingle())){ //
                isSuccess = materialsScheduleService.updateByInbound(warehouseDeliveryRecordDO.getBusinessOrder(),
                        warehouseDeliveryRecordDO.getMaterialNo(), realAmount, singleState, totalState, orgId);
                if(!isSuccess){
                    throw new Exception("生成入库记录时，更新领料单和详情状态失败");
                }
            }else if(BillDesc.BackOutbound.getDesc().equals(warehouseDeliveryRecordDO.getBusinessSingle())){ //更新回购出库单
                isSuccess = backOutboundService.updateByOutbound(warehouseDeliveryRecordDO.getBusinessOrder(),
                        warehouseDeliveryRecordDO.getMaterialNo(), realAmount, singleState, totalState, orgId);
                if(!isSuccess){
                    throw new Exception("生成出库记录时，更新回购出库单和详情状态失败");
                }
            }else if(BillDesc.ServiceBorrow.getDesc().equals(buinessSingle)){ //更新借用出库单
                isSuccess = serviceBorrowOutService.updateByOutbound(warehouseDeliveryRecordDO.getBusinessOrder(),
                        warehouseDeliveryRecordDO.getMaterialNo(), realAmount, singleState, totalState, orgId, false);
                if(!isSuccess){
                    throw new Exception("生成出库记录时，更新借用出库单和详情状态失败");
                }
            }else if(BillDesc.SalesOutNo.getDesc().equals(buinessSingle)){ //更新销售出库单
                isSuccess = salesOutBillService.updateByOutbound(warehouseDeliveryRecordDO.getBusinessOrder(),
                        warehouseDeliveryRecordDO.getMaterialNo(), realAmount, singleState, totalState, orgId, false);
                if(!isSuccess){
                    throw new Exception("生成出库记录时，更新销售出库单和详情状态失败");
                }
            }else if (BillDesc.ReturnMaterial.getDesc().equals(returnMaterialBusinessSingle)) { //更新归还单
                LogHelper.monitor("更新归还单出库状态");
                isSuccess = returnMaterialService.updateByOutbound(warehouseDeliveryRecordDO.getBusinessOrder(),
                        warehouseDeliveryRecordDO.getMaterialNo(), realAmount, singleState, totalState, orgId);
                if (!isSuccess) {
                    throw new Exception("生成出库记录时，更新归还单出库状态失败");
                }
            }else if(BillDesc.SendBill.getDesc().equals(buinessSingle)){ //更新送货单
                isSuccess = sendBillService.updateByOutbound(warehouseDeliveryRecordDO.getBusinessOrder(),
                        warehouseDeliveryRecordDO.getMaterialNo(), realAmount, singleState, totalState);
                if(!isSuccess){
                    throw new Exception("生成出库记录时，更新送货单和详情状态失败");
                }
            }else if(buinessSingle.startsWith(BillDesc.ZBCK.getDesc())){
                //转包出库单
                isSuccess = subcontractingOutService.updateByOutbound(warehouseDeliveryRecordDO.getBusinessOrder(),
                        warehouseDeliveryRecordDO.getMaterialNo(), realAmount, singleState, totalState);
                if(!isSuccess){
                    throw new Exception("生成出库记录时，更转包出库单和详情状态失败");
                }
            }

        }
        return code;
    }

    /**
     * @Author: WangKe
     * @Description: 无条码化管理的代理商确认出库
     * @Date: 2018/4/8 0008
     */
    @Transactional(rollbackFor = Exception.class)
    public ErrorCode receive(WarehouseDeliveryAddVO deliveryAddVO, String userId, String orgId)throws Exception{
        WarehouseDeliveryDO deliveryDO = warehouseDeliveryMapper.findByBusinessOrder(deliveryAddVO.getHeaderInfo().getBusinessOrder(), orgId);
        if(deliveryDO == null){
            return ErrorCode.IllegalArument;
        }
        if(deliveryDO.getStatus() == 2){
            return ErrorCode.OutboundDuplicate;
        }
        if(deliveryDO.getStatus() ==3){
            return ErrorCode.FinishBillYet;
        }
        List<WarehouseDeliveryDetailVO> deliveryDetailVOList = deliveryAddVO.getDetailList();
        if(ListUtil.isNullOrEmpty(deliveryDetailVOList)){
            return ErrorCode.IllegalArument;
        }
        //验证每个零件的储位编码
        Map<String, Map<String, String>> map = new HashMap<>();
        Map<String, String> warehouseMap;
        String warehouseCode = null;
        for(WarehouseDeliveryDetailVO detailVO : deliveryDetailVOList){
            if(StringUtil.isNullOrEmpty(detailVO.getLocationCode()) ){
//                throw new Exception("储位编码错误");
                continue;
            }
            if(StringUtil.isNullOrEmpty(detailVO.getAreaCode())
                    || StringUtil.isNullOrEmpty(detailVO.getWarehouseCode())){
                Map<String, Object> codeMap= warehouseAreaLocationDOMapper.findAllCode(detailVO.getLocationCode(),orgId);
                if(codeMap==null || codeMap.isEmpty()){
                    return ErrorCode.WarehouseLocationCodeError;
                }
                detailVO.setAreaCode(codeMap.get("AREA_CODE").toString());
                detailVO.setWarehouseCode(codeMap.get("WAREHOUSE_CODE").toString());
            }
            warehouseMap = new HashMap<>();
            warehouseMap.put("LOCATION_CODE", detailVO.getLocationCode());
            warehouseMap.put("AREA_CODE", detailVO.getAreaCode());
            warehouseMap.put("WAREHOUSE_CODE", detailVO.getWarehouseCode());
            map.put(detailVO.getMaterialNo(), warehouseMap);
            warehouseCode = detailVO.getWarehouseCode();
        }

        List<WarehouseDeliveryDetailDO> deliveryDetailDOList = warehouseDeliveryDetailMapper.findByBusinessOrder(deliveryDO.getBusinessOrder(), orgId);
        if(ListUtil.isNullOrEmpty(deliveryDetailDOList)){
            return ErrorCode.IllegalArument;
        }

        // 校验仓库是否允许非条码化入库
        if (StringUtils.isBlank(warehouseCode)){
            return ErrorCode.WarehouseLocationCodeError;
        }

        CompanyInfoDO companyInfoDO = companyInfoMapper.item(orgId);
        Integer isBarcode = companyInfoDO.getIsBarcode();
        int countIsBarCode = warehouseDOMapper.countIsBarCode(orgId, warehouseCode);
        if ((null == isBarcode || 0 == isBarcode) && countIsBarCode > 0){//非条码化且仓库允许条码化返回错误信息
            return ErrorCode.BarcodeWarehouseDoesNotAllowBarcodeOutbound;
        }


        boolean success;
        String buinessSingle = deliveryDO.getBusinessSingle();
        WarehouseDeliveryRecordDO warehouseDeliveryRecordDO;
        for(WarehouseDeliveryDetailDO deliveryDetailDO : deliveryDetailDOList){
            if (deliveryDetailDO.getStatus() == 3 || deliveryDetailDO.getStatus() == 2) {
                continue;
            }
            //新增出库记录
            warehouseDeliveryRecordDO = new WarehouseDeliveryRecordDO();
            BeanUtils.copyProperties(deliveryDetailDO, warehouseDeliveryRecordDO);

            warehouseMap = map.get(deliveryDetailDO.getMaterialNo());
            if(warehouseMap == null || warehouseMap.get("WAREHOUSE_CODE") == null || warehouseMap.get("AREA_CODE") == null){
                throw new Exception("储位编码错误");
            }
            warehouseDeliveryRecordDO.setId(fastGenClient.textGuid().getValue());
            warehouseDeliveryRecordDO.setLocationCode(warehouseMap.get("LOCATION_CODE"));
            warehouseDeliveryRecordDO.setAreaCode(warehouseMap.get("AREA_CODE"));
            warehouseDeliveryRecordDO.setWarehouseCode(warehouseMap.get("WAREHOUSE_CODE"));
            warehouseDeliveryRecordDO.setRealAmount(deliveryDetailDO.getAmount());
            warehouseDeliveryRecordDO.setOrgId(orgId);
            warehouseDeliveryRecordDO.setCreaterId(userId);
            warehouseDeliveryRecordDO.setCreaterName(commonService.getUserName(userId));
            warehouseDeliveryRecordDO.setCreateDate(new Date());
            warehouseDeliveryRecordDO.setDeliveryType(1);
            warehouseDeliveryRecordDO.setBarCode("0");

            success = warehouseDeliveryRecordMapper.insert(warehouseDeliveryRecordDO)>0;

            if(!success){
                throw new Exception("生成出库记录失败");
            }

            //更新库存
            success = warehouseInventoryService.updateByOutboundNoBarcode(warehouseDeliveryRecordDO, userId, orgId);
            if(!success){
                throw new Exception("更新库存失败");
            }

            //更新出库事物单状态
            success = warehouseDeliveryService.updateStateNoBarcode(warehouseDeliveryRecordDO.getBusinessOrder(), warehouseDeliveryRecordDO.getMaterialNo(),
                    2, warehouseDeliveryRecordDO.getOrgId());
            if(!success){
                throw new Exception("更新出库事物单状态失败");
            }

            //更新出库业务单据状态
            BigDecimal realAmount = warehouseDeliveryRecordDO.getRealAmount();
            Integer singleState = 2;
            Integer totalState = 2;
            if(BillDesc.RegionAllot.getDesc().equals(buinessSingle)){ //更新区域调拨单状态
                success = regionAllotDetailService.updateByOutbound(warehouseDeliveryRecordDO.getBusinessOrder(),
                        warehouseDeliveryRecordDO.getMaterialNo(), realAmount, singleState, totalState, orgId, false);
                if(!success){
                    throw new Exception("生成出库记录时，更新区域调拨单和详情状态失败");
                }
            }else if(BillDesc.AbnormalOutNo.getDesc().equals(buinessSingle)){ //更新非正常出库单状态
                success = abnormalOutService.updateByOut(warehouseDeliveryRecordDO.getBusinessOrder(),
                        warehouseDeliveryRecordDO.getMaterialNo(), realAmount, singleState+"", totalState+"", orgId, null, false);
                if(!success){
                    throw new Exception("生成出库记录时，更新其它出库单和详情状态失败");
                }
            }else if(BillDesc.DeliveryNo.getDesc().equals(buinessSingle)){ //更新发货通知单状态
                success = deliveryNoteService.updateByDelivery(warehouseDeliveryRecordDO.getBusinessOrder(),
                        warehouseDeliveryRecordDO.getMaterialNo(), realAmount, singleState+"", totalState+"", orgId, false);
                if(!success){
                    throw new Exception("生成出库记录时，更新发货通知单和详情状态失败");
                }
            }else if(BillDesc.AgentAllot.getDesc().equals(buinessSingle)){ //更新代理商间调拨单
                success = agentAllotDetailService.updateByOutbound(warehouseDeliveryRecordDO.getBusinessOrder(),
                        warehouseDeliveryRecordDO.getMaterialNo(), realAmount, singleState, totalState, orgId);
                if(!success){
                    throw new Exception("生成出库记录时，更新代理商间调拨单和详情状态失败");
                }
            }else if(BillDesc.ThreeOut.getDesc().equals(buinessSingle)){ //更新三包出库单
                success = threeGuaranteesOutService.updateByOutbound(warehouseDeliveryRecordDO.getBusinessOrder(),
                        warehouseDeliveryRecordDO.getMaterialNo(), realAmount, singleState, totalState, orgId, false);
                if(!success){
                    throw new Exception("生成出库记录时，更新三包出库单和详情状态失败");
                }
            }else if(BillDesc.BackOutbound.getDesc().equals(warehouseDeliveryRecordDO.getBusinessSingle())){ //更新回购出库单
                success = backOutboundService.updateByOutbound(warehouseDeliveryRecordDO.getBusinessOrder(),
                        warehouseDeliveryRecordDO.getMaterialNo(), realAmount, singleState, totalState, orgId);
                if(!success){
                    throw new Exception("生成出库记录时，更新回购出库单和详情状态失败");
                }
            }else if(BillDesc.ServiceBorrow.getDesc().equals(buinessSingle)){ //更新三包出库单
                success = serviceBorrowOutService.updateByOutbound(warehouseDeliveryRecordDO.getBusinessOrder(),
                        warehouseDeliveryRecordDO.getMaterialNo(), realAmount, singleState, totalState, orgId, false);
                if(!success){
                    throw new Exception("生成出库记录时，更新三包出库单和详情状态失败");
                }
            }else if(BillDesc.SalesOutNo.getDesc().equals(buinessSingle)){ //更新销售出库单
                success = salesOutBillService.updateByOutbound(warehouseDeliveryRecordDO.getBusinessOrder(),
                        warehouseDeliveryRecordDO.getMaterialNo(), realAmount, singleState, totalState, orgId, false);
                if(!success){
                    throw new Exception("生成出库记录时，更新销售出库单和详情状态失败");
                }
            }else if(BillDesc.MaterialsCode.getDesc().equals(warehouseDeliveryRecordDO.getBusinessSingle())){ //
                success = materialsScheduleService.updateByInbound(warehouseDeliveryRecordDO.getBusinessOrder(),
                        warehouseDeliveryRecordDO.getMaterialNo(), realAmount, singleState, totalState, orgId);
                if(!success){
                    throw new Exception("生成入库记录时，更新领料单和详情状态失败");
                }
            }
        }
        return ErrorCode.Success;
    }

    /**
     * @Author: WangKe
     * @Description: 更新相关记录
     * @Date: 15:10 2018/1/18 0018
     */
    public ErrorCode update(WarehouseDeliveryRecordVO warehouseDeliveryRecordVO){
        WarehouseDeliveryRecordDO warehouseDeliveryRecordDO = new WarehouseDeliveryRecordDO();
        BeanUtils.copyProperties(warehouseDeliveryRecordVO, warehouseDeliveryRecordDO);
        return warehouseDeliveryRecordMapper.updateByPrimaryKey(warehouseDeliveryRecordDO)>0? ErrorCode.Success: ErrorCode.WarehouseIdError;
    }

    /**
     * @Author: WangKe
     * @Description: 根据主键删除记录
     * @Date: 15:39 2018/1/17 0017
     */
    public ErrorCode delete(String id){
        int i = warehouseDeliveryRecordMapper.deleteByPrimaryKey(id);
        return i>0? ErrorCode.Success: ErrorCode.WarehouseIdError;
    }

    /**
     * @Author: WangKe
     * @Description: 根据主键列表删除记录
     * @Date: 2018/1/26 0026
     */
    public ErrorCode remove(List<String> ids){
        return warehouseDeliveryRecordMapper.remove(ids)>0? ErrorCode.Success: ErrorCode.WarehouseIdError;
    }

    /**
     * @Author: WangKe
     * @Description: 根据出库单号删除出库记录
     * @Date: 15:18 2018/1/17 0017
     */
    public ErrorCode deleteByDeliveryOrder(String deliveryOrder, String orgId){
        int i = warehouseDeliveryRecordMapper.deleteByDeliveryOrder(deliveryOrder, orgId);
        return i>0? ErrorCode.Success: ErrorCode.WarehouseIdError;
    }

    /**
     * @Author: WangKe
     * @Description: 根据出库单号删除出库详情记录
     * @Date: 2018/1/26 0026
     */
    public ErrorCode deleteByDeliveryOrderList(List<String> orderList, String orgId){
        int i = warehouseDeliveryRecordMapper.removeByOutOrderList(orderList, orgId);
        return i>0? ErrorCode.Success: ErrorCode.WarehouseIdError;
    }

    /**
     * @Author: WangKe
     * @Description: 查询出库记录列表
     * @Date: 17:04 2018/1/17 0017
     */
    public PageCommonVO list(SearchCommonVO<WarehouseDeliveryRecordVO> condition) {
        PageCommonVO<WarehouseDeliveryRecordVO> pageCommonVO = new PageCommonVO();
        PageHelperPlus.orderBy("create_date desc");
        PageHelperPlus.startPage(condition.getPageNum(), condition.getPageSize());
        if (!StringUtil.isNullOrEmpty(condition.getFilters().getLocationCode())) {
            String locationCode = condition.getFilters().getLocationCode();
            if (locationCode.toCharArray()[0] == '\uFEFF') {
                locationCode = locationCode.substring(1);
                condition.getFilters().setLocationCode(locationCode);
            }
        }
        List<WarehouseDeliveryRecordDO> doList = warehouseDeliveryRecordMapper.list(condition.getFilters());
        List<WarehouseDeliveryRecordVO> voList = new ArrayList<WarehouseDeliveryRecordVO>();
        for (WarehouseDeliveryRecordDO entity : doList) {
            WarehouseDeliveryRecordVO model = new WarehouseDeliveryRecordVO();
            BeanUtils.copyProperties(entity, model);
            voList.add(model);
        }
        pageCommonVO.setPageInfo(new PageInfo(doList));
        pageCommonVO.setPageInfoList(voList);
        return pageCommonVO;
    }

    /**
     * @Author: WangKe
     * @Description: 导出出库记录列表
     * @Date: 2018/2/7 0007
     */
    public void export(List<String> ids)throws Exception{
        invokeExport(warehouseDeliveryRecordMapper.findByIds(ids));
    }

    /**
     * @Author: WangKe
     * @Description: 导出全部出库记录列表
     * @Date: 2018/2/7 0007
     */
    public void exportAll(WarehouseDeliveryRecordVO condition)throws Exception{
        Integer count = warehouseDeliveryRecordMapper.findCountForExportAll(condition);
        List<WarehouseDeliveryRecordDO> dataList = new ArrayList<>();
        int times = count/500+1;
        for(int i=0; i<times; i++){
            PageHelperPlus.startPage(i + 1, 500, "create_date desc");
            dataList.addAll(warehouseDeliveryRecordMapper.list(condition));
        }
        invokeExport(dataList);
    }

    /**
     * @Author: WangKe
     * @Description: 导出出库记录列表
     * @Date: 2018/2/7 0007
     */
    private void invokeExport(List<WarehouseDeliveryRecordDO> doList)throws Exception{
        if(ListUtil.isNullOrEmpty(doList)){
            return;
        }
        String title = "出库记录数据导出";
        String[] rowsName = new String[]{"序号", "条码", "出库单号", "业务类别", "业务单号", "备注信息",
                "零件编码", "零件名称", "零件类型", "仓库编码", "仓库编码", "储位编码", "单位", "出库数量",
                "成本", "创建人", "创建日期"};
        List<Object[]>  dataList = new ArrayList<Object[]>();
        Object[] objs;
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        for (int i = 0; i < doList.size(); i++) {
            WarehouseDeliveryRecordDO DeliveryRecordDO = doList.get(i);
            objs = new Object[rowsName.length];
            objs[0] = i+1;
            objs[1] = DeliveryRecordDO.getBarCode();
            objs[2] = DeliveryRecordDO.getDeliveryOrder();
            objs[3] = DeliveryRecordDO.getBusinessSingle();
            objs[4] = DeliveryRecordDO.getBusinessOrder();
            objs[5] = DeliveryRecordDO.getNote();
            objs[6] = DeliveryRecordDO.getMaterialNo();
            objs[7] = DeliveryRecordDO.getMaterialName();
            objs[8] = DeliveryRecordDO.getMaterialType();
            objs[9] = DeliveryRecordDO.getWarehouseCode();
            objs[10] = DeliveryRecordDO.getAreaCode();
            objs[11] = DeliveryRecordDO.getLocationCode();
            objs[12] = DeliveryRecordDO.getUnit();
            objs[13] = DeliveryRecordDO.getAmount();
            objs[14] = DeliveryRecordDO.getCost();
            objs[15] = DeliveryRecordDO.getCreaterName();
            objs[16] = sdf.format(DeliveryRecordDO.getCreateDate());
            dataList.add(objs);
        }
        ExportUtil exportUtil = new ExportUtil(title, rowsName, dataList);
        exportUtil.export(response);
    }

    /**
     * @Author: WangKe
     * @Description: 获取出库业务单已出库和未出库的数量
     * @Date: 2018/3/14 0014
     */
    public InOutNumVO findAlreadyDeliveryNum(String businessOrder, String orgId){
        if (businessOrder != null && (businessOrder.startsWith(BillDesc.DeliveryReceiptNo.getDesc())
                ||businessOrder.startsWith(BillDesc.JCKDeliveryReceiptNo.getDesc()))) {
            return findAlreadyDeliveryNumForReceipt(businessOrder, orgId);
        }
        List<WarehouseDeliveryDetailDO> detailDOList = warehouseDeliveryDetailMapper.findByBusinessOrder(businessOrder, orgId);
        if(ListUtil.isNullOrEmpty(detailDOList)){
            return new InOutNumVO();
        }
        Integer alreadyNum = 0;
        Integer notAlreadyNum = 0;
        Map<String, BigDecimal> map = new HashMap<>();
        List<BarcodeManageDO> barcodeManageDOList = barcodeManageMapper.findAlreadyOutbound(businessOrder, orgId);
        if(CollectionUtils.isNotEmpty(barcodeManageDOList)){
            for(BarcodeManageDO barcodeManageDO : barcodeManageDOList){
                map.put(barcodeManageDO.getMaterialsNo(), barcodeManageDO.getCurrentQty());
            }
        }
        for(WarehouseDeliveryDetailDO detailDO : detailDOList){
            if(map.containsKey(detailDO.getMaterialNo()) && detailDO.getAmount().compareTo(detailDO.getRealAmount())<=0||detailDO.getStatus()==3){
                alreadyNum += 1;
            }else{
                notAlreadyNum += 1;
            }
        }
        return new InOutNumVO(alreadyNum, notAlreadyNum);
    }

    /**
     * @Author: WangKe
     * @Description: 获取出库业务单已出库和未出库的列表
     * @Date: 2018/3/14 0014
     */
    public List<WarehouseDeliveryDetailDO> findAlreadyDeliveryList(String businessOrder, Integer state, String orgId){
        if (businessOrder != null && (businessOrder.startsWith(BillDesc.DeliveryReceiptNo.getDesc())
                || businessOrder.startsWith(BillDesc.JCKDeliveryReceiptNo.getDesc()))) {
            return findAlreadyDeliveryListForReceipt(businessOrder, state, orgId);
        }
        List<WarehouseDeliveryDetailDO> alreadyList = new ArrayList<>();
        List<WarehouseDeliveryDetailDO> notAlreadyList = new ArrayList<>();
        List<WarehouseDeliveryDetailDO> detailDOList = warehouseDeliveryDetailMapper.findDetailOrderByLocation(businessOrder, orgId);
        if(ListUtil.isNullOrEmpty(detailDOList)){
            return alreadyList;
        }
        Map<String, BigDecimal> map = new HashMap<>();
        List<BarcodeManageDO> barcodeManageDOList = barcodeManageMapper.findAlreadyOutbound(businessOrder, orgId);
        if(CollectionUtils.isNotEmpty(barcodeManageDOList)){
            for(BarcodeManageDO barcodeManageDO : barcodeManageDOList){
                map.put(barcodeManageDO.getMaterialsNo(), barcodeManageDO.getCurrentQty());
            }
        }
        for(WarehouseDeliveryDetailDO detailDO : detailDOList){
            if(map.containsKey(detailDO.getMaterialNo()) && detailDO.getAmount().compareTo(detailDO.getRealAmount())<=0||detailDO.getStatus()==3){
                alreadyList.add(detailDO);
            }else{
                notAlreadyList.add(detailDO);
            }
        }
        if(state == 1){
            return alreadyList;
        }else{
            return notAlreadyList;
        }
    }

    public InOutNumVO findAlreadyDeliveryNumForReceipt(String businessOrder, String orgId) {
        List<WarehouseDeliveryDetailDO> detailDOList = listForReceipt(businessOrder);
        if (ListUtil.isNullOrEmpty(detailDOList)) {
            return new InOutNumVO();
        }
        int alreadyNum = 0;
        int notAlreadyNum = 0;
        for (WarehouseDeliveryDetailDO detailDO : detailDOList) {
            if (detailDO.getAmount().compareTo(detailDO.getRealAmount()) <= 0) {
                alreadyNum += 1;
            } else {
                notAlreadyNum += 1;
            }
        }
        return new InOutNumVO(alreadyNum, notAlreadyNum);
    }

    public List<WarehouseDeliveryDetailDO> findAlreadyDeliveryListForReceipt(String businessOrder, Integer state, String orgId) {
        List<WarehouseDeliveryDetailDO> alreadyList = new ArrayList<>();
        List<WarehouseDeliveryDetailDO> notAlreadyList = new ArrayList<>();
        List<WarehouseDeliveryDetailDO> detailDOList = listForReceipt(businessOrder);
        if (ListUtil.isNullOrEmpty(detailDOList)) {
            return alreadyList;
        }
        for (WarehouseDeliveryDetailDO detailDO : detailDOList) {
            if (detailDO.getAmount().compareTo(detailDO.getRealAmount()) <= 0) {
                alreadyList.add(detailDO);
            } else {
                notAlreadyList.add(detailDO);
            }
        }
        if (state == 1) {
            return alreadyList;
        } else {
            return notAlreadyList;
        }
    }

    private List<WarehouseDeliveryDetailDO> listForReceipt(String billNo) {
        DeliveryReceiptDO receiptDO=deliveryReceiptMapper.itemByNo(billNo);
        if (receiptDO==null) {
            return new ArrayList<>();
        }
        String billType=receiptDO.getBillType();
        List<WarehouseDeliveryDetailDO> list = null;
        if (BillDesc.DeliveryNo.getDesc().equals(billType)) {
            list = deliveryReceiptLinkMapper.listForDeliveryNote(billNo);
        }
        if (BillDesc.ThreeOut.getDesc().equals(billType)) {
            list = deliveryReceiptLinkMapper.listForThreeOut(billNo);
        }
        if (BillDesc.RegionAllot.getDesc().equals(billType)) {
            list = deliveryReceiptLinkMapper.listForRegionAllot(billNo);
        }
        if (BillDesc.AbnormalOutNo.getDesc().equals(billType)) {
            list = deliveryReceiptLinkMapper.listForAbnormalOut(billNo);
        }
        if (list == null) {
            list = new ArrayList<>();
        }
        return list;
    }

    /**
     * @Author: wxd
     * @Description: 进出口新增出库记录
     * @Date: 15:19 2018/1/17 0017
     */
    @Transactional(rollbackFor = Exception.class)
    public ErrorCode jckAdd(WarehouseDeliveryRecordAddVO warehouseDeliveryRecordVO, String userId, String orgId, boolean isLast) throws Exception{
        ActionResult<String> textResult = fastGenClient.textGuid();
        if (textResult.getCode() != ErrorCode.Success.getCode()) {
            return ErrorCode.IllegalArument;
        }

        //根据条码获取条码实体
        BarcodeManageDO barcode = barcodeManageMapper.item(warehouseDeliveryRecordVO.getBarCode(), orgId);
        if(barcode == null){
            return ErrorCode.WarehouseBarcodeNotFound;
        }
        if(barcode.getBarcodeFlag() == 0){
            return ErrorCode.TotalBarcodeNotEable;
        }
        //判断条码是否已经扫描出库
        if("2".equals(barcode.getBarcodeStatus())){
            return ErrorCode.WarehouseOutboundDuplicate;
        }

        //先判断库存表里是否有零件，零件数量是否够
        WarehouseInventoryDO warehouseInventoryDO = warehouseInventoryService.findByBarCode(warehouseDeliveryRecordVO.getBarCode(), orgId);
        if(warehouseInventoryDO == null || warehouseInventoryDO.getIsOut() == 1 ){
            return ErrorCode.WarehouseNotFound; //代表没有此零件
        }else if(warehouseInventoryDO.getStatus() == 1){
            return ErrorCode.WarehouseFrozen; //零件已冻结
        }else if(warehouseInventoryDO.getAmount().compareTo(warehouseDeliveryRecordVO.getAmount()) < 0){
            return ErrorCode.WarehouseAmountNotEqual; //代表零件数量不足
        }

        //根据业务单号和零件编码查询出库详情记录
        String businessOrder = warehouseDeliveryRecordVO.getBusinessOrder();
        businessOrder = businessOrder==null?"":businessOrder;
        String buinessSingle = "";

        if(businessOrder.length()>4){
            buinessSingle = businessOrder.substring(0, 4);
        }

        String returnMaterialBusinessSingle = businessOrder.substring(0, 5);

        //查找出库事物主记录，判断是否冲销
        WarehouseDeliveryDO deliveryDO = warehouseDeliveryMapper.findByBusinessOrder(businessOrder, orgId);
        if(deliveryDO == null){
            throw new Exception("未找到相关联的出库事物单主记录");
        }
        if(deliveryDO.getReverseState() != null && (deliveryDO.getReverseState() == 1 || deliveryDO.getReverseState() == 2)){
            throw new Exception("业务单据已被冲销，不允许出库");
        }
        //判断单据是否已经是完成状态
        if( deliveryDO.getStatus() != null && deliveryDO.getStatus() == 4){
            throw new Exception("业务单据已作废！");
        }

        //判断单据是否已经是完成状态
        if(deliveryDO.getStatus() != null && (deliveryDO.getStatus() == 2 || deliveryDO.getStatus() == 3)){
            throw new Exception("业务单据已完成！");
        }
        //判断是否退货
        if(deliveryDO.getIsReturn() != null && deliveryDO.getIsReturn() == 1){
            throw new Exception("业务单据已被退货，不允许出库");
        }

        //判断零件是否属于调出仓库零件
        if(deliveryDO.getWarehouseCode() != null && !deliveryDO.getWarehouseCode().equals(warehouseInventoryDO.getWarehouseCode())){
            throw new Exception("此零件不属于调出仓库零件");
        }

        if (null != deliveryDO.getWarehouseCode()){
            CompanyInfoDO companyInfoDO = companyInfoMapper.item(orgId);
            Integer isBarcode = companyInfoDO.getIsBarcode();
            int countIsBarCode = warehouseDOMapper.countIsBarCode(orgId, deliveryDO.getWarehouseCode());
            if ((null == isBarcode || 0 == isBarcode) && countIsBarCode <= 0){//非条码化企业且仓库不允许条码化返回错误信息
                throw new Exception(ErrorCode.NonBarcodedOutboundNotAllowBarCodeEntry.getDesc());
            }
        }

        //判断零件是否属于调出仓库中库区零件
        if(deliveryDO.getOutArea() != null && !deliveryDO.getOutArea().equals(warehouseInventoryDO.getAreaCode())){
            throw new Exception("此零件不属于调出库区零件");
        }

        //判断零件是否属于出库单中零件
        WarehouseDeliveryDetailVO deliveryDetailVO = new WarehouseDeliveryDetailVO();
        deliveryDetailVO.setBusinessOrder(businessOrder);
        deliveryDetailVO.setMaterialNo(warehouseInventoryDO.getMaterialNo());
        deliveryDetailVO.setOrgId(orgId);
        List<WarehouseDeliveryDetailDO> list = warehouseDeliveryDetailMapper.list(deliveryDetailVO);
        if(ListUtil.isNullOrEmpty(list)){
            throw new Exception("此零件不属于出库单中零件");
        }
        if (list.get(0).getStatus() == 2) {
            throw new Exception("此零件状态已完成");
        }
        if (list.get(0).getStatus() == 3) {
            throw new Exception("此零件状态已结单");
        }
        if(StringUtil.isNullOrEmpty(warehouseDeliveryRecordVO.getDeliveryReceiptNo())){
            if(list.get(0).getAmount().compareTo(warehouseInventoryDO.getAmount()) < 0){
                throw new Exception("实际出库数量不能大于计划出库数量");
            }
        }

        WarehouseDeliveryRecordDO warehouseDeliveryRecordDO = new WarehouseDeliveryRecordDO();
        BeanUtils.copyProperties(warehouseInventoryDO, warehouseDeliveryRecordDO);

        warehouseDeliveryRecordDO.setBarCode(warehouseInventoryDO.getBarCode());
        warehouseDeliveryRecordDO.setBusinessOrder(businessOrder);
        warehouseDeliveryRecordDO.setBusinessSingle(buinessSingle);
        warehouseDeliveryRecordDO.setAmount(warehouseDeliveryRecordVO.getAmount());
        warehouseDeliveryRecordDO.setId(textResult.getValue());
        warehouseDeliveryRecordDO.setCreateDate(new Date());
        warehouseDeliveryRecordDO.setCreaterId(userId);
        warehouseDeliveryRecordDO.setOrgId(orgId);
        warehouseDeliveryRecordDO.setDeliveryOrder(deliveryDO.getDeliveryOrder());
        warehouseDeliveryRecordDO.setCreaterName(commonService.getUserName(userId));
        warehouseDeliveryRecordDO.setDeliveryReceiptNo(warehouseDeliveryRecordVO.getDeliveryReceiptNo());

        boolean isSuccess = warehouseDeliveryRecordMapper.insert(warehouseDeliveryRecordDO)>0;
        ErrorCode code = isSuccess? ErrorCode.Success: ErrorCode.Failure;

        //出库成功，库存表里相关记录更新
        if(isSuccess){
            if(isLast){
                //如果是发运交接单出库，有可能是一个条码分多次出库，在最后一次出库时更新条码已出库状态
                ErrorCode barcodeErrorCode = barcodeService.deliveryUpdateBarcode(businessOrder,warehouseDeliveryRecordDO.getBarCode(), BarcodeStatus.Status.OutStorage, orgId, userId,warehouseDeliveryRecordDO.getCreateDate());
                if(barcodeErrorCode.getCode() != 0){
                    throw new Exception("生成出库记录时，更新条码状态失败");
                }
                isSuccess = warehouseInventoryService.saveByOutbound(warehouseInventoryDO, warehouseDeliveryRecordDO, userId);
                if(!isSuccess){
                    throw new Exception("生成出库记录时，更新库存状态失败");
                }
            }
            Map<String, BigDecimal> map = warehouseDeliveryDetailService.updateByOutbound(warehouseDeliveryRecordDO.getDeliveryOrder(),
                    warehouseDeliveryRecordDO.getMaterialNo(), warehouseDeliveryRecordVO.getAmount(), orgId);
            isSuccess = map.get("success").intValue()==1;
            if(!isSuccess){
                throw new Exception("生成出库记录时，更新出库事物单状态失败");
            }

            LogHelper.monitor("buinessSingle------------->"+buinessSingle);
            LogHelper.monitor("returnMaterialBusinessSingle----------------->"+returnMaterialBusinessSingle);

        }
        return code;
    }

    public Integer getDeliveryRecordCount(String orgId,String businessOrder,String materialsNo){
        if(StringUtils.isEmpty(businessOrder) || StringUtils.isEmpty(orgId)){
            return 0;
        }
        Integer countByBusinessOrder = warehouseDeliveryRecordMapper.findCountByBusinessOrder(businessOrder, orgId,materialsNo);
        return countByBusinessOrder == null ? 0 : countByBusinessOrder;
    }
}
